#include <graphics.h>
#include <ctime>
#include <mmsystem.h>
#include <cstdio>
#include <Windows.h>
#include <vector>
#include <string>
#include <filesystem>
#pragma comment(lib, "winmm.lib")

// ------------------- 常量定义 -------------------
#define INTERVAL 100
#define BLOCK_WIDTH 100
#define BLOCK_HEIGHT 150
#define INITIAL_BLOCK_SPEED 5
#define MAX_BLOCK_SPEED 10
#define GAME_AREA_TOP INTERVAL
#define GAME_AREA_BOTTOM 700
#define MAX_NOTES 1000
#define NOTE_LIFETIME 1000
#define GAME_WIN 1
#define GAME_LOSE 0

// ------------------- 枚举定义 -------------------
enum BlockType { NORMAL, BONUS, DANGER };
enum NoteType { WHOLE, HALF, QUARTER, EIGHTH };

// ------------------- 音符类 -------------------
class Note {
public:
    int x, y;
    COLORREF color;
    NoteType type;
    DWORD spawnTime;

    Note(int x, int y) : x(x), y(y), spawnTime(GetTickCount()) {
        color = RGB(rand() % 256, rand() % 256, rand() % 256);
        type = static_cast<NoteType>(rand() % 4);
    }

    void draw() const {
        int radius = 10;
        int stemLen = 40;
        int stemDir = -1;
        setlinecolor(color);
        setfillcolor(color);

        switch (type) {
        case WHOLE:
            setfillcolor(WHITE);
            fillcircle(x, y, radius);
            circle(x, y, radius);
            break;
        case HALF:
            setfillcolor(WHITE);
            fillcircle(x, y, radius);
            circle(x, y, radius);
            line(x + radius, y, x + radius, y + stemDir * stemLen);
            break;
        case QUARTER:
            fillcircle(x, y, radius);
            line(x + radius, y, x + radius, y + stemDir * stemLen);
            break;
        case EIGHTH: {
            fillcircle(x, y, radius);
            int x0 = x + radius, y0 = y;
            int x1 = x0, y1 = y0 + stemDir * stemLen;
            line(x0, y0, x1, y1);
            int pts[6] = { x1, y1, x1 + 20, y1 + stemDir * 15, x1, y1 + stemDir * 20 };
            fillpoly(3, pts);
            break;
        }
        }
    }

    bool isExpired() const {
        return GetTickCount() - spawnTime >= NOTE_LIFETIME;
    }
};

// ------------------- 方块类 -------------------
class Block {
public:
    int col;
    int y;
    bool active;
    BlockType type;

    Block(int col, int y) : col(col), y(y), active(false), type(NORMAL) {}

    void draw() const {
        int xPos = col * BLOCK_WIDTH;
        int yPos = y + GAME_AREA_TOP;

        if (type == BONUS) setfillcolor(YELLOW);
        else if (type == DANGER) setfillcolor(RED);
        else setfillcolor(BLACK);

        fillrectangle(xPos, yPos, xPos + BLOCK_WIDTH, yPos + BLOCK_HEIGHT);
    }

    void update(int speed) {
        y += speed;
        int absTop = y + GAME_AREA_TOP;
        int absBottom = absTop + BLOCK_HEIGHT;
        active = (absBottom >= GAME_AREA_TOP && absTop <= GAME_AREA_BOTTOM);
    }

    bool isBottomHit() const {
        return (y + GAME_AREA_TOP) > GAME_AREA_BOTTOM && type == NORMAL;
    }

    bool containsPoint(int px, int py) const {
        int absTop = y + GAME_AREA_TOP;
        int absBottom = absTop + BLOCK_HEIGHT;
        int xPos = col * BLOCK_WIDTH;
        return px >= xPos && px <= xPos + BLOCK_WIDTH &&
            py >= absTop && py <= absBottom;
    }
};

// ------------------- 游戏类 -------------------
class Game {
private:
    int score = 0;
    bool gameStarted = false;
    bool gameWon = false;
    int blockSpeed = INITIAL_BLOCK_SPEED;
    std::vector<Note*> notes;
    std::vector<Block*> blocks;
    bool musicPlaying = false;
    std::string musicPath = "resources/music.mp3";
    bool musicLoaded = false;  // 新增：标记音乐是否成功加载
public:
    Game() {
        // 初始化方块
        for (int i = 0; i < 4; i++) {
            blocks.push_back(new Block(rand() % 4, -BLOCK_HEIGHT * (i + 1)));
        }

        // 设置特殊方块
        int special = rand() % 4;
        int r = rand() % 100;
        if (r < 5) blocks[special]->type = DANGER;
        else if (r < 15) blocks[special]->type = BONUS;
    }

    ~Game() {
        cleanup();
    }

    void cleanup() {
        // 释放音符内存
        for (auto note : notes) {
            delete note;
        }
        notes.clear();

        // 释放方块内存
        for (auto block : blocks) {
            delete block;
        }
        blocks.clear();
    }

    void initBlocks() {
        // 清理现有方块
        for (auto block : blocks) {
            delete block;
        }
        blocks.clear();

        // 创建新方块
        for (int i = 0; i < 4; i++) {
            blocks.push_back(new Block(rand() % 4, -BLOCK_HEIGHT * (i + 1)));
        }

        // 设置特殊方块
        int special = rand() % 4;
        int r = rand() % 100;
        if (r < 5) blocks[special]->type = DANGER;
        else if (r < 15) blocks[special]->type = BONUS;
    }

    void spawnNote(int x, int y) {
        if (notes.size() >= MAX_NOTES) return;
        notes.push_back(new Note(x, y));
    }

    void cleanupNotes() {
        for (auto it = notes.begin(); it != notes.end(); ) {
            if ((*it)->isExpired()) {
                delete* it;
                it = notes.erase(it);
            }
            else {
                ++it;
            }
        }
    }

    void drawStartScreen() {
        cleardevice();
        settextstyle(50, 0, _T("黑体")); settextcolor(RED);
        outtextxy(80, 150, _T("别踩白块儿"));

        setfillcolor(RGB(70, 130, 180));
        fillrectangle(160, 300, 250, 350);
        settextstyle(25, 0, _T("黑体")); settextcolor(BLACK);
        outtextxy(173, 310, _T("Start"));

        settextstyle(20, 0, _T("黑体")); settextcolor(BLACK);
        outtextxy(110, 400, _T("点击黑色方块得分"));
        outtextxy(80, 430, _T("点击黄色方块+100分"));
        outtextxy(80, 460, _T("点击红色方块游戏结束"));
        outtextxy(50, 490, _T("黑色方块或红色方块触底游戏结束"));

        FlushBatchDraw();
    }

    bool checkStartButtonClick() {
        if (MouseHit()) {
            MOUSEMSG msg = GetMouseMsg();
            if (msg.uMsg == WM_LBUTTONDOWN &&
                msg.x >= 150 && msg.x <= 250 &&
                msg.y >= 300 && msg.y <= 350) {
                return true;
            }
        }
        return false;
    }

    void drawMap() {
        cleardevice();

        settextstyle(25, 0, _T("黑体")); settextcolor(RED);
        outtextxy(140, 45, _T("别踩白块儿"));

        TCHAR buf[32];
        _stprintf_s(buf, _T("Score: %d"), score);
        outtextxy(258, 20, buf);

        setlinestyle(PS_SOLID, 2); setlinecolor(RGB(59, 59, 59));
        for (int i = 0; i <= 4; i++) {
            line(i * BLOCK_WIDTH, GAME_AREA_TOP, i * BLOCK_WIDTH, GAME_AREA_BOTTOM);
            line(0, GAME_AREA_TOP + i * BLOCK_HEIGHT,
                4 * BLOCK_WIDTH, GAME_AREA_TOP + i * BLOCK_HEIGHT);
        }

        for (auto block : blocks) {
            block->draw();
        }

        for (auto note : notes) {
            note->draw();
        }

        FlushBatchDraw();
    }

    bool updateBlocks() {
        for (auto block : blocks) {
            block->update(blockSpeed);

            // 只有当方块完全离开屏幕底部才检测游戏结束
            if (block->isBottomHit()) {
                return false;
            }
        }
        return true;
    }

    bool handleMouseClick() {
        if (!MouseHit()) return true;
        MOUSEMSG msg = GetMouseMsg();
        if (msg.uMsg != WM_LBUTTONDOWN) return true;
        if (msg.y < GAME_AREA_TOP || msg.y > GAME_AREA_BOTTOM) return true;

        int col = msg.x / BLOCK_WIDTH;
        int best = -1, bestDist = GAME_AREA_BOTTOM;

        // 找到最底部的有效方块
        for (size_t i = 0; i < blocks.size(); i++) {
            if (blocks[i]->col == col && blocks[i]->active &&
                blocks[i]->containsPoint(msg.x, msg.y)) {
                int absBottom = blocks[i]->y + GAME_AREA_TOP + BLOCK_HEIGHT;
                int dist = GAME_AREA_BOTTOM - absBottom;
                if (dist < bestDist) {
                    bestDist = dist; best = i;
                }
            }
        }

        if (best < 0) return false;

        // 处理点击逻辑
        if (blocks[best]->type == BONUS) {
            score += 100;
            spawnNote(msg.x, msg.y);
        }
        else if (blocks[best]->type == DANGER) {
            return false;
        }
        else {
            score += 10;
            spawnNote(msg.x, msg.y);
        }

        // 删除被点击的方块
        delete blocks[best];
        blocks.erase(blocks.begin() + best);

        // 计算新方块的位置（找最低的方块)
        int minY = blocks[0]->y;
        for (auto block : blocks) {
            if (block->y < minY) minY = block->y;
        }

        // 创建新方块（确保在屏幕外)
        blocks.push_back(new Block(rand() % 4, minY - BLOCK_HEIGHT - 10));

        // 随机设置方块类型
        int r = rand() % 100;
        if (r < 5) blocks.back()->type = BONUS;
        else if (r < 7) blocks.back()->type = DANGER;
        else blocks.back()->type = NORMAL;

        // 调整游戏速度
        if (blockSpeed < MAX_BLOCK_SPEED) {
            blockSpeed = INITIAL_BLOCK_SPEED + score / 500;
            if (blockSpeed > MAX_BLOCK_SPEED) blockSpeed = MAX_BLOCK_SPEED;
        }

        return true;
    }

    bool isMusicPlaying() {
        if (!musicPlaying) return false;
        char status[128] = { 0 };
        mciSendString(("status BackgroundMusic mode"), status, sizeof(status), NULL);
        return strcmp(status, "playing") == 0;
    }

    void showGameEnd() {
        cleardevice();
        TCHAR buf[64];

        if (gameWon) {
            settextstyle(50, 0, _T("黑体"));
            settextcolor(GREEN);
            outtextxy(100, 300, _T("恭喜通关！"));
            _stprintf_s(buf, _T("最终得分: %d"), score);
            settextstyle(30, 0, _T("黑体"));
            outtextxy(150, 360, buf);
        }
        else {
            settextstyle(50, 0, _T("黑体"));
            settextcolor(RED);
            outtextxy(100, 300, _T("Game Over！"));
            _stprintf_s(buf, _T("最终得分: %d"), score);
            settextstyle(30, 0, _T("黑体"));
            outtextxy(150, 360, buf);
        }
        settextstyle(20, 0, _T("黑体"));
        outtextxy(150, 400, _T("点击任意位置退出"));
        FlushBatchDraw();
        while (true) {
            if (MouseHit() && GetMouseMsg().uMsg == WM_LBUTTONDOWN) break;
            Sleep(1);
        }
    }

    void run() {
        srand((unsigned)time(nullptr));
        initgraph(400, 700);
        setbkcolor(WHITE);
        cleardevice();
        BeginBatchDraw();

        drawStartScreen();
        while (!gameStarted) {
            if (checkStartButtonClick()) gameStarted = true;
            Sleep(1);
        }

        // 修复：音乐加载（用多字节字符串）
        musicLoaded = false;
        if (std::filesystem::exists(musicPath)) {  // 检查文件存在
            std::string openCmd = "open \"" + musicPath + "\" type mpegvideo alias BackgroundMusic";
            // 加载音乐
            if (mciSendString(openCmd.c_str(), NULL, 0, NULL) == 0) {
                mciSendString("play BackgroundMusic repeat", NULL, 0, NULL);  // 循环播放
                musicLoaded = true;
            } else {
                MessageBox(NULL, "无法加载音乐文件", "错误", MB_ICONERROR);
            }
        } else {
            MessageBox(NULL, "音乐文件未找到，游戏将继续但没有背景音乐", "警告", MB_ICONWARNING);
        }

        initBlocks();
        bool gameRunning = true;
        gameWon = false;

        while (gameRunning) {
            cleanupNotes();
            drawMap();

            if (!handleMouseClick()) {
                gameRunning = false;
                gameWon = false;
            }

            if (!updateBlocks()) {
                gameRunning = false;
                gameWon = false;
            }

            // 音乐结束判断（胜利条件）
            if (musicLoaded && !isMusicPlaying() && !gameWon) {
                gameRunning = false;
                gameWon = true;
            }


            Sleep(1);
        }

        // 停止并关闭音乐
        if (musicLoaded) {
            mciSendString("stop BackgroundMusic", NULL, 0, NULL);
            mciSendString("close BackgroundMusic", NULL, 0, NULL);
        }


        showGameEnd();
        EndBatchDraw();
        closegraph();
    }
};

int main() {
    Game game;
    game.run();
    return 0;
}